package compilationunit;


import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.*;




public class Parser {
	final int _EOF = 0;
	final int _ident = 1;
	final int _enteros = 2;
	final int _cadenaCar = 3;
	final int _boolean = 4;
	final int _char = 5;
	final int _class = 6;
	final int _false = 7;
	final int _int = 8;
	final int _new = 9;
	 final int _short = 10;
	 final int _static = 11;
	 final int _true = 12;
	 final int _void = 13;
	 final int _dosPuntos = 14;
	 final int _comma = 15;
	 final int _punto = 16;
	 final int _llaveIzda = 17;
	 final int _corcheteIzda = 18;
	 final int _parentesisIzda = 19;
	 final int _menos = 20;
	 final int _not = 21;
	 final int _mas = 22;
	 final int _llaveDer = 23;
	 final int _corcheteDer = 24;
	 final int _parentesisDer = 25;
	 final int _multiplicacion = 26;
	 final int _div = 27;
	 final int _menor = 28;
	 final int _mayor = 29;
	 final int _igual = 30;
	 final int _puntoComa = 31;
	 final int _doblesComillas = 32;
	 final int _interrogacion = 33;
	 final int maxT = 41;

	 final boolean T = true;
	 final boolean x = false;
	 final int minErrDist = 2;

	public  Token token;    // last recognized token   /* pdt */
	public Token la;       // lookahead token
	 int errDist = minErrDist;

     TablaSimbolos tablasimbolos = new TablaSimbolos();
     Simbolo simbolo = new Simbolo();
     Simbolo simbolo_aux = new Simbolo();
     Simbolo simbolo_aux2 = new Simbolo();
     Argumento argumento;
     LinkedList<Argumento> colaArgumento = new LinkedList<Argumento> ();
     int numargmetodo;
     int numargmetodo_aux;
     int aux = 0;
     java.io.PrintStream impresion = null;
     Tercetos tercetos = new Tercetos();
     Stack<String> pila_temp = new Stack();


    char tipo_asig = '-';
    int num_args;
     boolean vengode_decl_corch = false;
     boolean vengode_decl_parent = false;
     boolean vengode_arg_declaracion = false;
     boolean estoy_for = false;
     boolean hay_return = false;
     boolean es_constructor = false;



	 void SynErr (int n) {
		if (errDist >= minErrDist) Errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public  void SemErr (String msg) {
		if (errDist >= minErrDist) Errors.Error(token.line, token.col, msg); /* pdt */
		errDist = 0;
	}

	public  void SemError (String msg) {
		if (errDist >= minErrDist) Errors.Error(token.line, token.col, msg); /* pdt */
		errDist = 0;
	}

	public  void Warning (String msg) { /* pdt */
		if (errDist >= minErrDist) Errors.Warn(token.line, token.col, msg);
		errDist = 0;
	}

	public  boolean Successful() { /* pdt */
		return Errors.count == 0;
	}

	public  String LexString() { /* pdt */
		return token.val;
	}

	public  String LookAheadString() { /* pdt */
		return la.val;
	}


    public Simbolo Copia (Simbolo simb){
        Simbolo simbolo_aux3 = new Simbolo();
        simbolo_aux3.setId(simb.getId());
        simbolo_aux3.setTipo(simb.getTipo());
        simbolo_aux3.setCol(simb.getColumna());
        simbolo_aux3.setLinea(simb.getLinea());
        simbolo_aux3.setTipoRetorno(simb.getTipoRetorno());
        simbolo_aux3.setPublico(simb.getPublico());
        simbolo_aux3.setClaseRelacionada(simb.getClaseRelacionada());
        simbolo_aux3.setColaArgumentos(simb.getColaArgumentos());
        simbolo_aux3.setNumArgMetodo(simb.getNumArgMetodo());
        simbolo_aux3.setTipoEnVector(simb.getTipoEnVector());
        simbolo_aux3.setTamano(simb.getTamano());
        simbolo_aux3.setPos(simb.getPosicion());
        simbolo_aux3.setInicializado(simb.getInicializado());
        return simbolo_aux3;
    }

         void Esperado (int n){
        Expect(n);
        //Para cargar un nuevo token se usa este metodo
        //y dado que sólo hay un simbolo (global), este metodo se encarga de
        //llenar de basura sus campos para que no se lean valores del token anterior.

        simbolo.setPos(token.pos);     // token position in the source text (starting at 0)
        simbolo.setCol(token.col);     // token column (starting at 0)
        simbolo.setLinea(token.line);    // token line (starting at 1)
        simbolo.setId(token.val);
        simbolo.setClaseRelacionada("");
        simbolo.setColaArgumentos(null);
        simbolo.setNumArgMetodo(0);
        simbolo.setPublico(false);
        simbolo.setTamano(0);
        simbolo.setTipo('-');
        simbolo.setTipoEnVector('-');
        simbolo.setTipoRetorno('-');
        simbolo.setInicializado(false);

    }

         void Inicializa_aux(){

            try{
        simbolo_aux.setPos(0);     // token position in the source text (starting at 0)
        simbolo_aux.setCol(0);     // token column (starting at 0)
        simbolo_aux.setLinea(0);    // token line (starting at 1)
        simbolo_aux.setId("");
        simbolo_aux.setClaseRelacionada("");
        simbolo_aux.setColaArgumentos(null);
        simbolo_aux.setNumArgMetodo(0);
        simbolo_aux.setPublico(false);
        simbolo_aux.setTamano(0);
        simbolo_aux.setTipo('-');
        simbolo_aux.setTipoEnVector('-');
        simbolo_aux.setTipoRetorno('-');
        simbolo_aux.setInicializado(false);
            }catch(NullPointerException e){
                simbolo_aux = new Simbolo();
            }
        
        }


	 void Get () {
		for (;;) {
			token = la; /* pdt */
			la = Scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = token; /* pdt */
		}
	}

	 void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}

	 boolean StartOf (int s) {
		return set[s][la.kind];
	}

	 void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}

	 boolean WeakSeparator (int n, int syFol, int repFol) {
		boolean[] s = new boolean[maxT+1];
		if (la.kind == n) { Get(); return true; }
		else if (StartOf(repFol)) return false;
		else {
			for (int i=0; i <= maxT; i++) {
				s[i] = set[syFol][i] || set[repFol][i] || set[0][i];
			}
			SynErr(n);
			while (!s[la.kind]) Get();
			return StartOf(syFol);
		}
	}

	void compilationunit() {
		while (la.kind == 6) {
			Clases();
		}
	}

	void Clases() {
		Esperado(6);
		Esperado(1);
        simbolo.setTipo('x');
        if (tablasimbolos.t_actual != tablasimbolos.abuelo) SemError("Declaración de clase anidada");
        Simbolo simb = new Simbolo();
                simb = Copia(simbolo);
        int existe = tablasimbolos.InsertarSimbolo(simb, simb.getId());
        if (existe != 0) SemError("Nombre de clase repetido");
        tablasimbolos.CrearTablaPadre(simbolo.getId());
		Esperado(17);
		Miembros();
		Esperado(23);
        tablasimbolos.t_actual = tablasimbolos.abuelo;
	}

	 void TiposSimples() {
		if (la.kind == 8) {
            simbolo_aux.setTipo('e');
            simbolo_aux.setTipoEnVector('e');
            simbolo_aux.setTipoRetorno('e');
            simbolo_aux.setTamano(4);
			Get();
		} else if (la.kind == 4) {
            simbolo_aux.setTipo('b');
            simbolo_aux.setTipoEnVector('b');
            simbolo_aux.setTipoRetorno('b');
            simbolo_aux.setTamano(1);
			Get();
		} else if (la.kind == 13) {
             simbolo_aux.setTipoRetorno('n');
			Get();
		} else SynErr(42);
	}


//    Declaraciones = ["public" | "private"] TiposSimples (ident | "main") [";" | "["enteros"]" [";"] | "(" ["void" |ArgumentosDeclaracion] ")""{"Miembros"}"]


	 void Declaraciones() {
        Inicializa_aux();
		if (la.kind == 34 || la.kind == 35) {
			if (la.kind == 34) {
                simbolo_aux.setPublico(true);
				Get();
			} else {
				Get();
			}
		}
		TiposSimples();

		if (la.kind == 1) {
            simbolo_aux.setId(la.val);
            simbolo_aux.setCol(la.col);
            simbolo_aux.setPos(la.pos);
            simbolo_aux.setLinea(la.line);
            Get();
		} else if (la.kind == 36) {
            simbolo_aux.setId(la.val);
            simbolo_aux.setCol(la.col);
            simbolo_aux.setPos(la.pos);
            simbolo_aux.setLinea(la.line);
            if (!simbolo_aux.getPublico())
                SemErr("Falta modificador \"public\" en metodo main");
            tablasimbolos.setExisteMain(true);
			Get();
		} else SynErr(43);
		if (la.kind == 18 || la.kind == 19 || la.kind == 31) {
			if (la.kind == 31) {
                simbolo_aux.setTipoEnVector('-');
                simbolo_aux.setTipoRetorno('-');
                if (simbolo_aux.getId() == "main")
                    SynErr(25);
                Simbolo simb = new Simbolo();
                simb = Copia(simbolo_aux);
                int cop = simb.getTamano();
                simb.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                tablasimbolos.t_actual.setDesplazamiento(cop);
                int existe = tablasimbolos.InsertarSimbolo(simb, simb.getId());
                if (existe != 0) SemErr("Ya existe el identificador");
                Get();
			  } else if (la.kind == 18) {
                  simbolo_aux.setTipoRetorno('-');
                  simbolo_aux.setTipo('v');
                  if (simbolo_aux.getId() == "main")
                    SynErr(25);
                Get();
				Esperado(2);
                if (!token.val.equals("[") ){
                int entero = Integer.valueOf(token.val).intValue();
                if (entero < 0)
                    SemError("Imposible crear vector de tamaño negativo");
                simbolo_aux.setNumArgMetodo(entero);
                simbolo_aux.setTamano(entero * simbolo_aux.getTamano());
                }
				Esperado(24);
				Esperado(31);
                Simbolo simb = new Simbolo();
                simb = Copia(simbolo_aux);
                int cop = simb.getTamano();
                simb.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                tablasimbolos.t_actual.setDesplazamiento(cop);
                int existe = tablasimbolos.InsertarSimbolo(simb, simb.getId());
                if (existe != 0) SemErr("Ya existe el identitificador");
			} else {
                hay_return = false;
				Get();
                simbolo_aux.setTipo('m');
                simbolo_aux.setTamano(0);
                simbolo_aux.setTipoEnVector('-');
               if (StartOf(1)) {
					if (la.kind == 13) {
                        if (simbolo_aux.getId() != "main")
                    SynErr(36);
						Get();
					} else if (la.kind == 25)
                        simbolo_aux.setNumArgMetodo(0);
                    else {
                        Simbolo simbolo_aux3 = new Simbolo();
                        simbolo_aux3.setId(simbolo_aux.getId());
                        simbolo_aux3.setTipo(simbolo_aux.getTipo());
                        simbolo_aux3.setCol(simbolo_aux.getColumna());
                        simbolo_aux3.setLinea(simbolo_aux.getLinea());
                        simbolo_aux3.setTipoRetorno(simbolo_aux.getTipoRetorno());
                        simbolo_aux3.setPublico(simbolo_aux.getPublico());
                        simbolo_aux.setNumArgMetodo(0);
                        colaArgumento.clear();
                        numargmetodo = 0;
                        ArgumentosDeclaracion();
                        simbolo_aux.setId(simbolo_aux3.getId());
                        simbolo_aux.setTipo(simbolo_aux3.getTipo());
                        simbolo_aux.setCol(simbolo_aux3.getColumna());
                        simbolo_aux.setLinea(simbolo_aux3.getLinea());
                        simbolo_aux.setTipoRetorno(simbolo_aux3.getTipoRetorno());
                        
                        simbolo_aux.setPublico(simbolo_aux3.getPublico());
                        simbolo_aux.setTipo('m');
                        
					}
				}
                Simbolo simb = new Simbolo();
                simb = Copia(simbolo_aux);
                simb.setTamano(0);
                int cop = simb.getTamano();
                simb.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                tablasimbolos.t_actual.setDesplazamiento(cop);

                int existe1 = tablasimbolos.InsertarSimbolo(simb, simb.getId());
                if (existe1 != 0)
                    SemErr("Ya existe un metodo con ese identificador en esta clase");
                tablasimbolos.CrearTablaHijo(simb.getId());
                int args = simb.getNumArgMetodo();
                Queue colaArgumento = simb.getColaArgumentos();
                Argumento arg;
                Object arrayArg[] = null;
                if (args > 0)
                arrayArg = colaArgumento.toArray();
                int i = 0;
                while (args > 0){
                    arg = (Argumento) arrayArg[i];
                    i = i+1;
                    Inicializa_aux();
                    simbolo_aux.setTipo(arg.getTipo());
                    if (arg.getTipo()=='e') simbolo_aux.setTamano(4);
                    if (arg.getTipo()=='b') simbolo_aux.setTamano(1);
                    if (arg.getTipo()=='v') {
                       int X = simbolo_aux.getNumArgMetodo();
                       int Y = simbolo_aux.getTipoEnVector();
                       if (arg.getTipo()=='e') simbolo_aux.setTamano(4 * X);
                       else if (arg.getTipo()=='b') simbolo_aux.setTamano(X);
                    }
                    simbolo_aux.setId(arg.getNombre());
                    Simbolo simb2 = new Simbolo();
                    simb2 = Copia(simbolo_aux);
                    int cop3 = simb2.getTamano();
                    simb2.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                    tablasimbolos.t_actual.setDesplazamiento(cop3);
                    int existe = tablasimbolos.InsertarSimbolo(simb2, simb2.getId());
                    if (existe != 0) SemErr("Existen dos parámetros con el mismo identificador");
                    args = args - 1;
                }
				Esperado(25);
				Esperado(17);
                Miembros();

                if ((simb.getTipoRetorno()=='n')&&(hay_return==true)){
                    SemErr("El metodo devuelve void.");
                }
                else if ((hay_return == false)&&(simb.getTipoRetorno()!='n')){
                    SemErr("El metodo debe contener al menos un \"return\".");
                }
                Esperado(23);
                tablasimbolos.t_actual = tablasimbolos.t_actual.getSuperior();
                //Aqui deberia destruir esta tabla
			}
		}
	}




     void DeclaracionesArgumentos(){
        TiposSimples();
        char typo = simbolo_aux.getTipo();
        Esperado(1);
        argumento = new Argumento(typo, token.val);
        colaArgumento.offer(argumento);
        simbolo_aux.setColaArgumentos(colaArgumento);
        simbolo_aux.setNumArgMetodo(simbolo_aux.getNumArgMetodo() + 1);
        numargmetodo = simbolo_aux.getNumArgMetodo() + 1;
    }

	 void ArgumentosDeclaracion() {
		if (StartOf(1)) {
			DeclaracionesArgumentos();
			while (la.kind == 15) {
				Get();
				ArgumentosDeclaracion();
			}
		}
	}

	 void Miembros() {
		while (StartOf(2)) {
			if (StartOf(1)) {
				Declaraciones();
			} else {
				Sentencias();
			}
		}
	}




//    static void Asignaciones() {
//		Expect(1);
//		if (StartOf(4)) {
//			if (la.kind == 16) {
//				Get();
//				Expect(1);
//				if (la.kind == 19 || la.kind == 31) {
//					if (la.kind == 19) {
//						Get();
//						Argumentos();
//						Expect(25);
//						Expect(31);
//					} else {
//						Get();
//					}
//				}
//			} else if (la.kind == 1) {
//				Get();
//				Expect(31);
//			} else if (la.kind == 18) {
//				Get();
//				Expresion();
//				Expect(24);
//			} else {
//				Get();
//				if (StartOf(5)) {
//					if (StartOf(1)) {
//						ArgumentosDeclaracion();
//					} else {
//						Argumentos();
//					}
//				}
//				Expect(25);
//				if (la.kind == 17 || la.kind == 31) {
//					if (la.kind == 17) {
//						Get();
//						Miembros();
//						Expect(23);
//					} else {
//						Get();
//					}
//				}
//			}
//		}
//		ALLMetodo();
//	}


//    Asignaciones = ident ["." ident ["("Argumentos")" ";"] | ident ";" | "["Expresion"]" | "("[ArgumentosDeclaracion | Argumentos]")"["{"Miembros"}" |";"]] ALLMetodo

	 void Asignaciones() {
        Inicializa_aux();
        Esperado(1);
        if (la.line==24){
            int x;
            x = 234;
        }
        Simbolo asigna_simbol = new Simbolo();
        asigna_simbol = tablasimbolos.Buscar(simbolo.getId());
        if (asigna_simbol == null && (la.kind != 1))
                   SemErr("El identificador es desconocido");

		if (StartOf(3)) {
			if (la.kind == 16) {
                if (asigna_simbol == null){
                   SemErr("El identificador no se corresponde con ningún objeto declarado");
                }
                if (asigna_simbol.getTipo() != 'o') {
                    SemError("Se esperaba una variable tipo objeto");
                }
                String clase_asociada = asigna_simbol.getClaseRelacionada();
                TablaSimb tio;
                tio = tablasimbolos.BuscarTio(clase_asociada);
                if (tio== null) SemError("No existe la clase relacionada");
				Get();
				Esperado(1);
                asigna_simbol = tablasimbolos.BuscarEn(tio, simbolo.getId());
                if (asigna_simbol == null) SemErr("No existe ningún atributo o metodo en la clase "+clase_asociada+" con ese identificador");

                if (la.kind == 19 || la.kind == 31) {
                   
				if (la.kind == 19) {
                    if (asigna_simbol.getTipo() != 'm') SemErr("Sólo un método puede llevar argumentos");
                    //if (tipo_asig != 'm') SemErr("Sólo un método puede llevar argumentos");
                    else{
                        if (asigna_simbol.getColaArgumentos() != null)
                        colaArgumento = asigna_simbol.getColaArgumentos();
                    }
                        Get();
                        Argumentos();
                        Esperado(25);
                        if (la.kind == 31)
                        Esperado(31);
                        else
                            if (la.kind != 15)
                                SemErr("Se esperaba ;");
                    }
                }
                if (la.kind == 31){
                   Esperado(31);

                }               
             }
			 else if (la.kind == 1) {
                TablaSimb tio;
                tio = tablasimbolos.BuscarTio(token.val);
                if (tio == null) SemErr("No existe ninguna clase declarada con ese identificador");
                else{
                    Simbolo simb = new Simbolo(la.val, 'o',la.line);
                    simb.setCol(la.col);
                    simb.setPos(la.pos);
                    simb.setClaseRelacionada(token.val);
                    simb.setTamano(0);
                    int cop = simb.getTamano();
                    simb.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                    tablasimbolos.t_actual.setDesplazamiento(cop);
                    int existe = tablasimbolos.InsertarSimbolo(simb, la.val);
                    if (existe != 0) SemErr("Existe otro elemento con el mismo identificador");
                    Get();
                    Esperado(31);
                }
			} else if (la.kind == 18) {
                if (asigna_simbol== null) SemErr("No existe ningún vector con ese identificador");
				Get();
                tupla_id c;
				c = Expresion();
                if (c.getTipo() != 'e') SemError("La expresion debe ser matemática");
                tipo_asig = asigna_simbol.getTipoEnVector();
				Esperado(24);
			}else if ((la.kind == 19) || (la.kind == 31)) {

                if (asigna_simbol.getTipo()=='x'){
                        es_constructor = true;
                        asigna_simbol.setTipo('m');
                    }
				if ((la.kind == 19)&&(es_constructor == false)) {
                    
                    if (asigna_simbol.getTipo() != 'm') SemErr("Sólo un método puede llevar argumentos");
                    //if (tipo_asig != 'm') SemErr("Sólo un método puede llevar argumentos");
                    else{
                        if (asigna_simbol.getColaArgumentos() != null)
                        colaArgumento = asigna_simbol.getColaArgumentos();
                        numargmetodo = asigna_simbol.getNumArgMetodo();
                        numargmetodo_aux = numargmetodo;
                        aux = 0;
                    }
                    
                        Get();

                        Argumentos();
                        Esperado(25);
                        if (la.kind == 31)
                        Esperado(31);
                        else
                            if (la.kind != 15)
                                SemErr("Se esperaba ;");
                    
                }

                if ((la.kind==19)&&(es_constructor == true)){
                    asigna_simbol.setLinea(token.line);
                    asigna_simbol.setCol(token.col);
                    asigna_simbol.setPos(token.pos);
                    Get();
                    simbolo_aux.setNumArgMetodo(0);
                    colaArgumento.clear();
                    numargmetodo = 0;
                    ArgumentosDeclaracion();
                    LinkedList<Argumento> colaArgumento_aux = new LinkedList<Argumento> ();
                    int numargmetodo_aux = simbolo_aux.getNumArgMetodo();
                    colaArgumento_aux = simbolo_aux.getColaArgumentos();
                    asigna_simbol.setColaArgumentos(colaArgumento_aux);
                    asigna_simbol.setNumArgMetodo(numargmetodo_aux);
                    asigna_simbol.setTamano(0);
                    int cop = asigna_simbol.getTamano();
                    asigna_simbol.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                    tablasimbolos.t_actual.setDesplazamiento(cop);
                    int existe1 = tablasimbolos.InsertarSimbolo(asigna_simbol, asigna_simbol.getId());
                if (existe1 != 0)
                    SemErr("Ya existe un metodo con ese identificador en esta clase");
                tablasimbolos.CrearTablaHijo(asigna_simbol.getId());
                int args = asigna_simbol.getNumArgMetodo();
                LinkedList colaArgumento = new  LinkedList<Argumento> ();
                colaArgumento = asigna_simbol.getColaArgumentos();
                simbolo_aux = Copia(asigna_simbol);
                Argumento arg;
                Object arrayArg[];
                arrayArg = colaArgumento.toArray();

                int i = 0;
                while (args > 0){
                    arg = (Argumento) arrayArg[i];
                    i = i+1;
                    Inicializa_aux();
                    simbolo_aux.setTipo(arg.getTipo());
                    if (arg.getTipo()=='e') simbolo_aux.setTamano(4);
                    if (arg.getTipo()=='b') simbolo_aux.setTamano(1);
                    if (arg.getTipo()=='v') {
                       int X = simbolo_aux.getNumArgMetodo();
                       int Y = simbolo_aux.getTipoEnVector();
                       if (arg.getTipo()=='e') simbolo_aux.setTamano(4 * X);
                       else if (arg.getTipo()=='b') simbolo_aux.setTamano(X);
                    }
                    simbolo_aux.setId(arg.getNombre());
                    Simbolo simb2 = new Simbolo();
                    simb2 = Copia(simbolo_aux);
                    int cop2 = simb2.getTamano();
                    simb2.setTamano(tablasimbolos.t_actual.getDesplazamiento());
                    tablasimbolos.t_actual.setDesplazamiento(cop2);
                    int existe = tablasimbolos.InsertarSimbolo(simb2, simb2.getId());
                    if (existe != 0) SemErr("Existen dos parámetros con el mismo identificador");
                    args = args - 1;
                }
                    
                    Esperado(25);
                    Esperado(17);
                    Miembros();
                    Esperado(23);
                    tablasimbolos.t_actual = tablasimbolos.t_actual.getSuperior();
                    es_constructor = false;
                }
 
                } else if (la.kind == 25) {
            
                Get();
				if (StartOf(4)) {
					if (StartOf(5)) {
						ArgumentosDeclaracion();
					} else {
						Argumentos();
					}
				}
				Esperado(25);
				if (la.kind == 17 || la.kind == 31) {
					if (la.kind == 17) {
						Get();
						Miembros();
						Esperado(23);
					} else {
						Get();
					}
				}
			}
        }
		
		ALLMetodo();
	}

	 void Argumentos() {

        if (colaArgumento == null) {
            if (numargmetodo != 0)
            SemError("cola de argumentos vacía");
            return;
        }else{
        argumento = colaArgumento.poll();
        numargmetodo = numargmetodo - 1;
        
        if (aux>numargmetodo_aux) SemError("Número de argumentos incorrecto");
        aux = aux + 1;
		if (StartOf(6)) {
            //expresion debe comprobar que si argumento no es vacio
            //su tipo de retorno debe coincidir con el tipo del argumento.
			Expresion();
			while (la.kind == 15) {
				Get();
				Argumentos();
			}
            if ((numargmetodo >0)&&(la.kind != 15)) SemError("Número de argumentos incorrecto");
		}else if (numargmetodo > 0) SemError("Número de argumentos incorrecto");
        }
	
     }

	 void ALLMetodo() {
		if (la.kind == 30) {
			Get();
			Expresion();
            if (estoy_for != true)
			Esperado(31);
		}
	}

	 void ES() {
		if (la.kind == 37) {
			Escribir();
		} else if (la.kind == 38) {
			Leer();
		} else SynErr(44);
	}

	 void Escribir() {
		Esperado(37);
		Esperado(19);
		if (StartOf(6)) {
			if (la.kind == 3) {
				Get();
			} else {
				Expresion();
			}
		}
		Esperado(25);
		Esperado(31);
	}

	 void Leer() {
		Esperado(38);
		Esperado(19);
		Expresion();
		Esperado(25);
		Esperado(31);
	}

	 void Retorno() {

		Esperado(39);
        hay_return = true;
		if (StartOf(6)) {
			Expresion();
		}
		Esperado(31);
	}

	 void For() {
		Esperado(40);
		Esperado(19);
		Asignaciones();
		Expresion();
		Esperado(31);
        estoy_for = true;
		Asignaciones();
        estoy_for = false;
		Esperado(25);
		if (la.kind == 17) {
			Get();
			while (StartOf(7)) {
				Sentencias();
			}
			Esperado(23);
		} else if (StartOf(7)) {
			Sentencias();
		} else SynErr(45);
	}

	 void Sentencias() {
		if (la.kind == 1) {
			Asignaciones();
		} else if (la.kind == 39) {
			Retorno();
		} else if (la.kind == 37 || la.kind == 38) {
			ES();
		} else if (la.kind == 40) {
			For();
		} else SynErr(46);
	}

     //	 char Expresion() {
//        char c1,c2;
//		c2 = Expresion2();
//		c1 = Expresion1();
//        if (c1=='-') {
//            return c2;
//        }
//        if (c1!= c2) SemErr("Tipos incompatibles en expresion");
//        return c1;
//	}


     tupla_id Expresion() {
         tupla_id c;
		if (StartOf(1)) {
			if (la.kind == 33) {
				Get();
                tupla_id c1;
				c1 = Expresion();
                if (c1.getTipo() != 'b') SemError("Se esperaba una expresión booleana");
				Esperado(14);
				c = Expresion();
				c = Expresion();
                if (c.getTipo() == '-') SemError("Expresion incorrecta");
                return c;
			}
		} else if (StartOf(2)) {
			c = Expresion1();
            if (c.getTipo() == '-') SemError("Expresion incorrecta");
            return c;
		} else SynErr(44);
         return new tupla_id("",'-');
	}


//	 char Expresion2() {
//        char c1,c2;
//		c1 = Expresion3();
//		c2 = Expresion21();
//        return c1;
//	}
//
//	 char Expresion1() {
//        char c1,c2;
//		if (la.kind == 33) {
//			Get();
//			c1 = Expresion();
////            if ((c1 != 'e')||(c1!= 'b')) SemError("Tipo no permitido en operador condicional");
//			Esperado(14);
//			c2 = Expresion();
////            if ((c1 != 'e')||(c1!= 'b')) SemError("Tipo no permitido en operador condicional");
//            if (c1!=c2) SemError("Tipos incompatibles en operador condicional");
//			Expresion1();
//            return c1;
//		}
//        return '-';
//	}
//
//	 char Expresion3() {
//        char c1,c2;
//		c1=Expresion4();
//		c2=Expresion31();
//        if ((c1!=c2)&&(c1!='o')) SemError("Tipos incompatibles");
//        return c1;
//	}
//
//	 char Expresion21() {
//        char c,c1,c2;
//        c = '-';
//		if (la.kind == 28) {
//			Get();
////            c = 'b';
////			c1 = Expresion3();
////            if (c1!='b') SemError("Se esperaba boolean");
////			c2 = Expresion21();
////             if (c2!='b') SemError("Se esperaba boolean");
//            c1 = Expresion3();
//            c2 = Expresion21();
//            if (c1!='e') SemError("Tipos incompatibles en expresion");
//            c = '-';
//            return c;
//		}
//        return c;
//	}
//
//	 char Expresion4() {
//        char c,c1 ;
//        c = '-';
//		if (la.kind == 21) {
//			Get();
//            c = 'b';
//			c1 = Expresion4();
//            if (c!=c1) SemError("Se esperaba un boolean");
//		} else if (StartOf(8)) {
//			c = Expresion5();
//		} else SynErr(47);
//        return c;
//	}
//
//	 char Expresion31() {
//        char c1,c2;
//        boolean id1, id2;
//		if (la.kind == 22) {
//            pila_temp.push("+");
//			Get();
//            c1 = Expresion4();
//			c2 = Expresion31();
//
//            if ((c1 != c2) || (c1 !='e')) SemError("Se esperaba un entero");
//		}
//        return 'e';
//	}
//
//	 char Expresion5() {
//        char c = '-';
//		switch (la.kind) {
//		case 19: {
//			Get();
//			c = Expresion();
//			Esperado(25);
//			break;
//		}
//		case 9: {
//			Get();
//            c = 'o'; //Estamos haciendo "Mesa = new Mueble();"
//			Esperado(1);
//            Simbolo expr_simbol = new Simbolo();
//            expr_simbol = tablasimbolos.Buscar(simbolo.getId());
//            if (expr_simbol != null) SemError("Mal uso del constructor");
//            if (expr_simbol == null){
//                TablaSimb tio;
//                tio = tablasimbolos.BuscarTio(simbolo.getId());
//                if (tio == null) SemError("No existe la clase "+simbolo.getId());
//                expr_simbol = tablasimbolos.BuscarEn(tio, simbolo.getId());//Busco el constructor en la clase.
//                if (expr_simbol==null) SemError("El constructor no esta declarado");
//                if (expr_simbol.getTipo()!='m') SemError("El constructor debe ser un método");
//            }
//			Esperado(19);
//            if (expr_simbol.getColaArgumentos() != null)
//            colaArgumento = expr_simbol.getColaArgumentos();
//            numargmetodo = expr_simbol.getNumArgMetodo();
//            numargmetodo_aux = numargmetodo;
//            aux = 0;
//            if (numargmetodo != 0)
//			Argumentos();
//			Esperado(25);
//        	break;
//		}
//		case 1: {
//
////            if ((token.kind == 19)||(token.kind == 14)||(token.kind == 33)||(token.kind == 39)||(token.kind == 31)){
////                simbolo.setId(la.val);
////            }
//
//            pila_temp.push(la.val);
//            simbolo.setId(la.val);
//            Simbolo expr_simbol = new Simbolo();
//            expr_simbol = tablasimbolos.Buscar(simbolo.getId());
//            if (expr_simbol==null) SemError("Variable no declarada");
//			Get();
//            if (expr_simbol!=null)
//            c = expr_simbol.getTipo();
//			if (la.kind == 16 || la.kind == 18 || la.kind == 19) {
//				if (la.kind == 16) {
//					Get();
//					Esperado(1);
//                    TablaSimb tio;
//                    tio = tablasimbolos.BuscarTio(expr_simbol.getClaseRelacionada());
//                    if (tio == null) SemError("No se encontró la clase relacionada");
//                    expr_simbol = tablasimbolos.BuscarEn(tio, simbolo.getId());
//                    if (expr_simbol == null) SemError("No se encontró el atributo o método en la clase relacionada");
//					if (la.kind == 19) {
//                        if (expr_simbol.getTipo()!= 'm') SemError("Se esperaba un método");
//                        c = expr_simbol.getTipoRetorno();
//						Get();
//                        if (expr_simbol.getColaArgumentos() != null)
//                        colaArgumento = expr_simbol.getColaArgumentos();
//                        numargmetodo = expr_simbol.getNumArgMetodo();
//                        numargmetodo_aux = numargmetodo;
//                        aux = 0;
//						Argumentos();
//						Esperado(25);
//					}else
//                        c = expr_simbol.getTipo();
//				} else if (la.kind == 19) {
//					Get();
//                    if (expr_simbol.getTipo()!='m') SemError("Se esperaba un método");
//                    if (expr_simbol.getColaArgumentos() != null)
//                    colaArgumento = expr_simbol.getColaArgumentos();
//                    numargmetodo = expr_simbol.getNumArgMetodo();
//                    numargmetodo_aux = numargmetodo;
//                    aux = 0;
//					Argumentos();
//                    c = expr_simbol.getTipoRetorno();
//					Esperado(25);
//				} else {
//                    if (expr_simbol.getTipo() != 'v')
//					Get();
//                    char c_aux;
//					c_aux = Expresion();
//                    if (c_aux != 'e') SemError("Se esperaba un entero");
//                    c = expr_simbol.getTipoEnVector();
//					Esperado(24);
//				}
//			}
//			break;
//		}
//		case 2: {
//			Get();
//            c = 'e';
//			break;
//		}
//		case 3: {
//			Get();
//            c = 's';
//			break;
//		}
//		case 12: {
//			Get();
//            c = 'b';
//			break;
//		}
//		case 7: {
//			Get();
//            c = 'b';
//			break;
//		}
//		default: SynErr(48); break;
//		}
//        return c;
//	}

   tupla_id Expresion1() {
       tupla_id c1 = new tupla_id("",'-');
		if (StartOf(2)) {
            tupla_id c2;
			c2 = Expresion2();
            return c2;
		} else if (StartOf(2)) {
			c1 = Expresion1();
            if (c1.getTipo() != 'e') SemError("Se esperaba una expresión entera");
			Esperado(28);
            tupla_id c2;
			c2 = Expresion2();
            if (c2.getTipo() != 'e') SemError("Se esperaba una expresión entera");
            return new tupla_id("",'b');
		} else SynErr(48);
       return new tupla_id("",'-');
	}

	tupla_id Expresion2() {
        tupla_id c2, c3;
		if (StartOf(2)) {
			c3 = Expresion3();
            return c3;
		} else  if (StartOf(2)) {
			c2 = Expresion2();
            if (c2.getTipo() != 'e') SemError("Se esperaba una expresión entera");
			Esperado(22);
			c3 = Expresion3();
            if (c3.getTipo() != 'e') SemError("Se esperaba una expresión entera");
            return new tupla_id("",'e');
		} else SynErr(49);
        return new tupla_id("",'-');
	}

	tupla_id Expresion3() {
        tupla_id c3, c4;
		if (la.kind == 21) {
			Get();
			c3 = Expresion3();
            if (c3.getTipo() != 'b') SemError("Se esperaba expresión booleana");
            return new tupla_id("",'b');
		} else if (la.kind != 21) {
			c4 = Expresion4();
            return c4;
		} else SynErr(50);
        return new tupla_id("",'-');
	}

	tupla_id Expresion4() {
        tupla_id c4 = new tupla_id("",'-');
		switch (la.kind) {
            //Parentesis izquierda.
		case 19: {
			Get();
			c4 = Expresion();
			Esperado(25);
			break;
		}
        //Constructor
        // Bh = new Bicicleta();

		case 9: {
            c4 = new tupla_id("",'o');
			Get();
			Esperado(1);
            c4.setId(simbolo.getId());
            Simbolo expr_simbol = new Simbolo();
            expr_simbol = tablasimbolos.Buscar(simbolo.getId());
            if (expr_simbol != null) SemError("Mal uso del constructor");
            if (expr_simbol == null){
                TablaSimb tio;
                tio = tablasimbolos.BuscarTio(simbolo.getId());
                if (tio == null) SemError("No existe la clase "+simbolo.getId());
                expr_simbol = tablasimbolos.BuscarEn(tio, simbolo.getId());//Busco el constructor en la clase.
                if (expr_simbol==null) SemError("El constructor no esta declarado");
                if (expr_simbol.getTipo()!='m') SemError("El constructor debe ser un método");
            }
			Esperado(19);
            if (expr_simbol.getColaArgumentos() != null)
            colaArgumento = expr_simbol.getColaArgumentos();
            numargmetodo = expr_simbol.getNumArgMetodo();
            numargmetodo_aux = numargmetodo;
            aux = 0;
            if (numargmetodo != 0)
			Argumentos();
			Esperado(25);
			break;
		}
        //Identificador
        // num; || metodo(x,y) || vect[5] || bh.freno(0) || bh.num_ruedas
        // ident; || ident() || ident[] || ident.ident() || ident.ident ||
		case 1: {
            String ident = la.val;
            simbolo.setId(la.val);
            Simbolo expr_simbol = new Simbolo();
            expr_simbol = tablasimbolos.Buscar(simbolo.getId());
            if (expr_simbol==null) SemError("Variable no declarada");
			Get();
            if (expr_simbol!=null)
            c4.setTipo(expr_simbol.getTipo());
			if (la.kind == 16 || la.kind == 18 || la.kind == 19) {
				if (la.kind == 16) {
					Get();
					Esperado(1);
                    ident = ident + "." + la.val;
                    TablaSimb tio;
                    tio = tablasimbolos.BuscarTio(expr_simbol.getClaseRelacionada());
                    if (tio == null) SemError("No se encontró la clase relacionada");
                    expr_simbol = tablasimbolos.BuscarEn(tio, simbolo.getId());
                    if (expr_simbol == null) SemError("No se encontró el atributo o método en la clase relacionada");
					//dentro de un objeto -> Parentesis izquierda.
                    if (la.kind == 19) {
                        if (expr_simbol.getTipo()!= 'm') SemError("Se esperaba un método");
                        c4.setTipo(expr_simbol.getTipoRetorno()) ;
						Get();
                        if (expr_simbol.getColaArgumentos() != null)
                        colaArgumento = expr_simbol.getColaArgumentos();
                        numargmetodo = expr_simbol.getNumArgMetodo();
                        numargmetodo_aux = numargmetodo;
                        aux = 0;
						Argumentos();
						Esperado(25);
					}else
                        c4.setTipo( expr_simbol.getTipo());
                        c4.setId(ident);
                    //parentesis izquierda.
				} else if (la.kind == 19) {
					Get();
                    if (expr_simbol.getTipo()!='m') SemError("Se esperaba un método");
                    if (expr_simbol.getColaArgumentos() != null)
                    colaArgumento = expr_simbol.getColaArgumentos();
                    numargmetodo = expr_simbol.getNumArgMetodo();
                    numargmetodo_aux = numargmetodo;
                    aux = 0;
					Argumentos();
                    c4.setTipo(expr_simbol.getTipoRetorno());
                    c4.setId(ident);
					Esperado(25);
				} else {
                    if (expr_simbol.getTipo() != 'v') SemError("Se esperaba un vector");
					Get();
                    tupla_id c_aux;
                    c_aux = Expresion();
                    if (c_aux.getTipo() != 'e') SemError("Se esperaba un entero");
                    c4.setTipo(expr_simbol.getTipoEnVector());
                    c4.setId(ident);
					Esperado(24);
				}
			}
			break;
		}
		case 2: {
            //Aqui se generan temporales para enteros
            c4.setId(tercetos.darTemporal());
            c4.setTipo('e');
			Get();
			break;
		}
		case 3: {
            c4.setId(tercetos.darTemporal());
            c4.setTipo('s');
			Get();
			break;
		}
		case 12: {
            c4.setId(tercetos.darTemporal());
            c4.setTipo('b');
			Get();
			break;
		}
		case 7: {
            c4.setId(tercetos.darTemporal());
            c4.setTipo('b');
			Get();
			break;
		}
		default: SynErr(51); break;
		}
        return c4;
	}



	public void Parse() {
		la = new Token();
		la.val = "";
		Get();
		compilationunit();
        ImprimeTablaSimbolos();
        
		Esperado(0);
        
	}

	private  boolean[][] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,x,x,x, T,x,x,x, T,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x},
		{x,T,x,x, T,x,x,x, T,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,T,T,T, T,x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,T,T, T,x,x,T, T,T,x,x, T,T,x,x, x,x,x,T, x,T,x,x, x,T,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x},
		{x,x,x,x, T,x,x,x, T,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x},
		{x,T,T,T, x,x,x,T, x,T,x,x, T,x,x,x, x,x,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,x,x},
		{x,T,T,T, x,x,x,T, x,T,x,x, T,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}

	};




public void ImprimeTablaSimbolos(){
     try{
    impresion=new PrintStream( new java.io.FileOutputStream("F:\\Universidad\\4º\\Compiladores\\pruebas_definitivas\\tablaimpresa.txt"));
    }catch(FileNotFoundException e){
          System.err.println("Nombre de archivo desconocido");
      }

    ImprimeAbuelo();
    System.out.println("\n");
     System.out.println("\n");
     impresion.println("");
     impresion.println("");
    ImprimePadres();
     System.out.println("");
      System.out.println("");
      impresion.println("");
      impresion.println("");
    ImprimeHijos();
     System.out.println("");
      System.out.println("");
      impresion.println("");
      impresion.println("");
    impresion.close();
    }

public void ImprimeAbuelo(){
    System.out.println("++++++++++++++TABLA ABUELO++++++++++++++");
    impresion.println("++++++++++++++TABLA ABUELO++++++++++++++");
    System.out.println("- Desplazamiento total : " + tablasimbolos.abuelo.getDesplazamiento());
    impresion.println("- Desplazamiento total : " + tablasimbolos.abuelo.getDesplazamiento());

    int index = 0;
    System.out.println("Contiene las siguientes entradas ");
    impresion.println("Contiene las siguientes entradas ");
    HashMap aux = (HashMap) tablasimbolos.abuelo.getTabla();
    ImprimeTabla(aux);
  
}

public void ImprimeTabla(HashMap tabla){
    System.out.println("Simbolos.......");
    impresion.println("Simbolos.......");
    System.out.println("-----------------------------------------");
    impresion.println("-----------------------------------------");


    Iterator it;
    it = tabla.values().iterator();

    while(it.hasNext()){
            Simbolo s = (Simbolo)it.next();
            ImprimeSimbolo(s);}
}


public void ImprimePadres(){
    System.out.println("************************************************************ ");
    impresion.println("************************************************************ ");
    System.out.println("***********Imprimiendo las tablas padre (clases)************ ");
    impresion.println("***********Imprimiendo las tablas padre (clases)************ ");
    System.out.println("************************************************************ ");
    impresion.println("************************************************************ ");

    Iterator it_padres;
    it_padres = tablasimbolos.padres.iterator();
    while (it_padres.hasNext()){
        TablaSimb tabla = (TablaSimb) it_padres.next();
        System.out.println("xxxxxxxxxxxxxxxxxxx  Imprimiendo la tabla [" +tabla.getNombre()+"]  xxxxxxxxxxxxxxxxxxx");
         impresion.println("xxxxxxxxxxxxxxxxxxx  Imprimiendo la tabla [" +tabla.getNombre()+"]  xxxxxxxxxxxxxxxxxxx");
        System.out.println("Desplazamiento total: " + tabla.getDesplazamiento());
        impresion.println("Desplazamiento total: " + tabla.getDesplazamiento());
        System.out.println("Tabla superior: " + tabla.getSuperior().getNombre());
        impresion.println("Tabla superior: " + tabla.getSuperior().getNombre());
        ImprimeTabla(tabla.getTabla());
         System.out.println("");
         impresion.println("");
         System.out.println("");
         impresion.println("");

    }
}

public void ImprimeHijos(){
    System.out.println("************************************************************ ");
    impresion.println("************************************************************ ");
    System.out.println("***********Imprimiendo las tablas hijo (métodos)************ ");
    impresion.println("***********Imprimiendo las tablas hijo (métodos)************ ");
    System.out.println("************************************************************ ");
    impresion.println("************************************************************ ");

    Iterator it_hijos;
    it_hijos = tablasimbolos.hijos.iterator();
    while (it_hijos.hasNext()){
        TablaSimb tabla = (TablaSimb) it_hijos.next();
        System.out.println("xxxxxxxxxxxxxxxxxxx  Imprimiendo la tabla [" +tabla.getNombre()+"]  xxxxxxxxxxxxxxxxxxx");
         impresion.println("xxxxxxxxxxxxxxxxxxx  Imprimiendo la tabla [" +tabla.getNombre()+"]  xxxxxxxxxxxxxxxxxxx");
        System.out.println("Desplazamiento total: " + tabla.getDesplazamiento());
        impresion.println("Desplazamiento total: " + tabla.getDesplazamiento());
        System.out.println("Tabla superior: " + tabla.getSuperior().getNombre());
        impresion.println("Tabla superior: " + tabla.getSuperior().getNombre());
        ImprimeTabla(tabla.getTabla());
         System.out.println("");
         impresion.println("");
         System.out.println("");
         impresion.println("");

    }
}

public void ImprimeSimbolo(Simbolo simbol){
    
    System.out.println("Simbolo:  " + simbol.getId());
    impresion.println("Simbolo:  " + simbol.getId());
    System.out.println("Tipo:  " + simbol.getTipo());
    impresion.println("Tipo:  " + simbol.getTipo());
    System.out.println("Linea:  " + simbol.getLinea());
    impresion.println("Linea:  " + simbol.getLinea());
    System.out.println("Tamaño:  " + simbol.getTamano());
    impresion.println("Tamaño:  " + simbol.getTamano());
    if (simbol.getTipo()=='m'){
    System.out.println("Numero de argumentos:  " + simbol.getNumArgMetodo());
    impresion.println("Numero de argumentos:  " + simbol.getNumArgMetodo());
    if (simbol.getColaArgumentos() != null){
        Iterator it;
        it = simbol.getColaArgumentos().iterator();
        int i = 0;
        while (it.hasNext()){
            Argumento lista = (Argumento) it.next();
            i = i+1;
            System.out.println("    Argumento " +i+":  ");
            System.out.println("        nombre:  " + lista.getNombre());
            System.out.println("        tipo:  " + lista.getTipo());
            impresion.println("    Argumento " +i+":  ");
            impresion.println("        nombre:  " + lista.getNombre());
            impresion.println("        tipo:  " + lista.getTipo());
        }
    }
    System.out.println("Tipo de retorno:  " + simbol.getTipoRetorno());
    impresion.println("Tipo de retorno:  " + simbol.getTipoRetorno());
    }



    System.out.println("-----------------------------------------");
    impresion.println("-----------------------------------------");

}

} // end Parser

/* pdt - considerable extension from here on */

class ErrorRec {
	public int line, col, num;
	public String str;
	public ErrorRec next;

	public ErrorRec(int l, int c, String s) {
		line = l; col = c; str = s; next = null;
	}

} // end ErrorRec
class tupla_id{
    String id;
    char tipo;

    public tupla_id(String ide, char type){
        id = ide;
        tipo = type;
    }

    public String getId(){
        return id;
    }

    public char getTipo(){
        return tipo;
    }

    public void setId(String ide){
        id = ide;
    }

    public void setTipo(char type){
        tipo = type;
    }

}

class Errors {

	public static int count = 0;                                     // number of errors detected
	public static String errMsgFormat = "file {0} : ({1}, {2}) {3}"; // 0=file 1=line, 2=column, 3=text
	static String fileName = "";
	static String listName = "";
	static boolean mergeErrors = false;
	static PrintWriter mergedList;

	static ErrorRec first = null, last;
	static boolean eof = false;

	static String getLine() {
		char ch, CR = '\r', LF = '\n';
		int l = 0;
		StringBuffer s = new StringBuffer();
		ch = (char) Buffer.Read();
		while (ch != Buffer.EOF && ch != CR && ch != LF) {
			s.append(ch); l++; ch = (char) Buffer.Read();
		}
		eof = (l == 0 && ch == Buffer.EOF);
		if (ch == CR) {  // check for MS-DOS
			ch = (char) Buffer.Read();
			if (ch != LF && ch != Buffer.EOF) Buffer.pos--;
		}
		return s.toString();
	}

	static private String Int(int n, int len) {
		String s = String.valueOf(n);
		int i = s.length(); if (len < i) len = i;
		int j = 0, d = len - s.length();
		char[] a = new char[len];
		for (i = 0; i < d; i++) a[i] = ' ';
		for (j = 0; i < len; i++) {a[i] = s.charAt(j); j++;}
		return new String(a, 0, len);
	}

	static void display(String s, ErrorRec e) {
		mergedList.print("**** ");
		for (int c = 1; c < e.col; c++)
			if (s.charAt(c-1) == '\t') mergedList.print("\t"); else mergedList.print(" ");
		mergedList.println("^ " + e.str);
	}

	public static void Init (String fn, String dir, boolean merge) {
		fileName = fn;
		listName = dir + "listing.txt";
		mergeErrors = merge;
		if (mergeErrors)
			try {
				mergedList = new PrintWriter(new BufferedWriter(new FileWriter(listName, false)));
			} catch (IOException e) {
				Errors.Exception("-- could not open " + listName);
			}
	}

	public static void Summarize () {
		if (mergeErrors) {
			ErrorRec cur = first;
			Buffer.setPos(0);
			int lnr = 1;
			String s = getLine();
			while (!eof) {
				mergedList.println(Int(lnr, 4) + " " + s);
				while (cur != null && cur.line == lnr) {
					display(s, cur); cur = cur.next;
				}
				lnr++; s = getLine();
			}
			if (cur != null) {
				mergedList.println(Int(lnr, 4));
				while (cur != null) {
					display(s, cur); cur = cur.next;
				}
			}
			mergedList.println();
			mergedList.println(count + " errors detected");
			mergedList.close();
		}
		switch (count) {
			case 0 : System.out.println("Parsed correctly"); break;
			case 1 : System.out.println("1 error detected"); break;
			default: System.out.println(count + " errors detected"); break;
		}
		if (count > 0 && mergeErrors) System.out.println("see " + listName);
	}

	public static void storeError (int line, int col, String s) {
		if (mergeErrors) {
			ErrorRec latest = new ErrorRec(line, col, s);
			if (first == null) first = latest; else last.next = latest;
			last = latest;
		} else printMsg(fileName, line, col, s);
	}

	public static void SynErr (int line, int col, int n) {
		String s;
		switch (n) {
			case 0: s = "EOF Esperadoed"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "enteros expected"; break;
			case 3: s = "cadenaCar expected"; break;
			case 4: s = "boolean expected"; break;
			case 5: s = "char expected"; break;
			case 6: s = "class expected"; break;
			case 7: s = "false expected"; break;
			case 8: s = "int expected"; break;
			case 9: s = "new expected"; break;
			case 10: s = "short expected"; break;
			case 11: s = "static expected"; break;
			case 12: s = "true expected"; break;
			case 13: s = "void expected"; break;
			case 14: s = "dosPuntos expected"; break;
			case 15: s = "comma expected"; break;
			case 16: s = "punto expected"; break;
			case 17: s = "llaveIzda expected"; break;
			case 18: s = "corcheteIzda expected"; break;
			case 19: s = "parentesisIzda expected"; break;
			case 20: s = "menos expected"; break;
			case 21: s = "not expected"; break;
			case 22: s = "mas expected"; break;
			case 23: s = "llaveDer expected"; break;
			case 24: s = "corcheteDer expected"; break;
			case 25: s = "parentesisDer expected"; break;
			case 26: s = "multiplicacion expected"; break;
			case 27: s = "div expected"; break;
			case 28: s = "menor expected"; break;
			case 29: s = "mayor expected"; break;
			case 30: s = "igual expected"; break;
			case 31: s = "puntoComa expected"; break;
			case 32: s = "doblesComillas expected"; break;
			case 33: s = "interrogacion expected"; break;
			case 34: s = "\"public\" expected"; break;
			case 35: s = "\"private\" expected"; break;
			case 36: s = "\"main\" expected"; break;
			case 37: s = "\"print\" expected"; break;
			case 38: s = "\"read\" expected"; break;
			case 39: s = "\"return\" expected"; break;
			case 40: s = "\"for\" expected"; break;
			case 41: s = "??? expected"; break;
			case 42: s = "invalid TiposSimples"; break;
			case 43: s = "invalid Declaraciones"; break;
			case 44: s = "invalid ES"; break;
			case 45: s = "invalid For"; break;
			case 46: s = "invalid Sentencias"; break;
			case 47: s = "invalid Expresion4"; break;
			case 48: s = "invalid Expresion5"; break;
			default: s = "error " + n; break;
		}
		storeError(line, col, s);
		count++;
	}

	public static void SemErr (int line, int col, int n) {
		storeError(line, col, ("error " + n));
		count++;
	}

	public static void Error (int line, int col, String s) {
		storeError(line, col, s);
		count++;
	}

	public static void Warn (int line, int col, String s) {
		storeError(line, col, s);
	}

	public static void Exception (String s) {
		System.out.println(s);
		System.exit(1);
	}

	private static void printMsg(String fileName, int line, int column, String msg) {
		StringBuffer b = new StringBuffer(errMsgFormat);
		int pos = b.indexOf("{0}");
		if (pos >= 0) { b.replace(pos, pos+3, fileName); }
		pos = b.indexOf("{1}");
		if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, line); }
		pos = b.indexOf("{2}");
		if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, column); }
		pos = b.indexOf("{3}");
		if (pos >= 0) b.replace(pos, pos+3, msg);
		System.out.println(b.toString());
	}

} // end Errors
